﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Fsxm.LispEdit;
using FastColoredTextBoxNS;
using System.Text.RegularExpressions;
using System.IO;
using System.Windows.Forms;
using Plugin_AutoInsertLib.Properties;


[assembly: PluginClass(typeof(Plugin_AutoInsertLib.AutoInsertLib))]
namespace Plugin_AutoInsertLib
{
    public class AutoInsertLib : Plugin
    {

        public override void Start()
        {
            var item = AddMenuItem("插入函数库函数", null);

            item.Click += Item_Click;
            item.ShortcutKeys = System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F;

            foreach (Control itxem in EditApp.Controls)
            {
                if (itxem is ToolStrip)
                {
                    ToolStrip FstoolStrip = itxem as ToolStrip;
                    var item1 = FstoolStrip.Items.Add("强势插入");
                    item1.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;
                    item1.Image = Resources.insert;

                    item1.Click += Item_Click;

                    break;
                }
            }

        }


        private void Item_Click(object sender, EventArgs e)
        {
            var edit = ActivateEdit;
            if (edit == null) return;

            string txt = FindAllInsertText(edit.Text, LibFuntions());
            if (txt.Length > 0)
            {
                InsertText(edit, "\r\n\r\n");
                InsertText(edit, ";;;======================================\r\n");
                InsertText(edit, ";;;===========以下为内裤部分=============\r\n");
                InsertText(edit, ";;;======================================\r\n");
                InsertText(edit, txt);
            }
        }

        //todo
        // 1.扫描本文档的函数
        // 2.扫描待插入函数的位置









        /// <summary>
        /// 插入字符串，并进行缩进处理
        /// </summary>
        /// <param name="fctb">当前活动文档对象</param>
        /// <param name="text">字符串</param>
        private void InsertText(LispTextBox fctb, string text)
        {
            fctb.BeginAutoUndo();
            fctb.Selection.BeginUpdate();
            fctb.BeginUpdate();

            fctb.Selection.Expand();
            fctb.Selection.Start = new Place(fctb.TextSource[fctb.TextSource.Count - 1].Count, fctb.TextSource.Count - 1);
            var start = fctb.Selection.Start.iLine;

            fctb.InsertText(text);
            int end = fctb.Selection.Start.iLine;
            for (int i = start; i < end; i++)
            {
                fctb.DoAutoIndent(i);
            }
            var po = fctb[start].Count;
            fctb.Selection = new Range(fctb, po, start, po, start);

            fctb.EndAutoUndo();
            fctb.Selection.EndUpdate();
            fctb.EndUpdate();
        }

        /// <summary>
        /// 根据文件名，行号，在文件中查找函数的完整代码
        /// </summary>
        /// <param name="file">文件名</param>
        /// <param name="line">行号</param>
        /// <param name="funname">函数名</param>
        /// <param name="encoding">文件编码</param>
        /// <returns>函数的完整代码字符串</returns>
        private string ReadFun(string file, int line, string funname)
        {
            int index = 0;
            int zuonum = 0;
            List<string> res = new List<string>();
            Regex myreg = new Regex(@"(\()\s*(defun\s*[^'()\s]*)(?=\s)");
            if (!File.Exists(file))
            {
                return "";
            }
            try
            {
                using (FileStream open = new FileStream(file, FileMode.Open, FileAccess.Read))
                {
                    using (StreamReader read = new StreamReader(open, Encoding.Default))
                    {
                        while (!read.EndOfStream)
                        {
                            string tmp = read.ReadLine();

                            if (index >= line)
                            {
                                zuonum += LeftBracket(tmp);
                                res.Add(tmp);
                                if (zuonum == 0)
                                {

                                    break;
                                }

                            }

                            index++;
                        }


                    }
                }
                if (res.Count == 0)
                {
                    return "";
                }
                else
                {
                    return string.Join("\r\n", res.ToArray());
                }

            }
            catch
            {

                return "";
            }

        }

        /// <summary>
        /// 计算左括号-右括号的数量，以此来判断是否在函数内部
        /// </summary>
        /// <param name="str">要计算的字符串</param>
        /// <param name="isBlock">是否为块注释</param>
        /// <returns>返回左括号-右括号的差</returns>
        private int LeftBracket(string str)
        {
            int zuo = 0;
            int you = 0;
            bool isstr = false;

            for (int i = 0; i < str.Length; i++)
            {
                char item = str[i];
                char prev;
                if (i >= 1)
                {
                    prev = str[i - 1];
                }
                else
                {
                    prev = ' ';
                }

                if (item == '\"') //如果遇到字符串，设置进入字符串为true
                {
                    if (prev == '\\')
                    {
                        if (str[i - 2] == '\\')
                        {
                            isstr = !isstr;
                        }
                        else
                        {
                            continue;
                        }

                    }
                    else
                    {
                        isstr = !isstr;
                    }
                }
                if (isstr == true) //如果位于字符串中
                {
                    continue;
                }
                else //不位于字符串中
                {
                    if (item.ToString() == ";") //是注释
                    {

                        break;
                    }
                    else if (item.ToString() == "(")
                    {
                        zuo++;
                    }
                    else if (item.ToString() == ")")
                    {
                        you++;
                    }
                    else
                    {
                        continue;
                    }
                }
            }
            return zuo - you;
        }

        /// <summary>
        /// 查找用户待插入函数
        /// </summary>
        /// <param name="str">文本字符串</param>
        /// <returns>用户函数list</returns>
        private List<string> FindUserFuns(string str)
        {



            List<string> res = new List<string>();
            MatchCollection matchsAll = Regex.Matches(str, @"(?<!;+.*)((?<=[\(']\s*)[^'""()\s]*(?=\s*))", RegexOptions.IgnoreCase | RegexOptions.Multiline); //全部匹配

            MatchCollection matchsDefun = Regex.Matches(str, @"(?<=defun\s+)([^'()\s]*)(?=\s*)", RegexOptions.IgnoreCase | RegexOptions.Multiline);//匹配当前文件定义的函数

            //MatchCollection matchfen = Regex.Matches(str, @"(?<=;.*[\(']\s*)[^'""()\s]*(?=[\s\)])", RegexOptions.IgnoreCase | RegexOptions.Multiline);//匹配注释里的函数


            foreach (Match mt in matchsAll)
            {
                string mtValue = mt.Value.ToLower();
                if (!res.Contains(mtValue) && mtValue != "")
                {
                    res.Add(mtValue);
                }

            }

            List<string> tmp2 = new List<string>();
            foreach (Match item in matchsDefun) // 当前定义
            {
                string mtValue = item.Value.ToLower();
                if (!tmp2.Contains(mtValue) && mtValue != "")
                {
                    tmp2.Add(mtValue);
                }
            }

            //List<string> tmp4 = new List<string>();
            //foreach (Match item in matchfen) // ;;;
            //{
            //    string mtValue = item.Value.ToLower();
            //    if (!tmp4.Contains(mtValue) && mtValue != "")
            //    {
            //        tmp4.Add(mtValue);
            //    }
            //}

            var SystemFunList = Read.AllPublicUsers["0"].Keys.Select(d => d.ToLower()).ToList();
            res.RemoveAll(data => tmp2.Contains(data) || /*tmp4.Contains(data) ||*/ SystemFunList.Contains(data));
            return res.Union(new List<string>()).ToList();
        }
        /// <summary>
        /// 提取内裤函数
        /// </summary>
        /// <returns>内裤函数及函数代码的字典</returns>
        private Dictionary<string, string> LibFuntions()
        {
            var all = Read.AllPublicUsers;


            LispTextBox fctb = ActivateEdit;
            var doc = fctb.Doc;
            var currentFileName = doc.FileName;

            var all1 = doc.LastRead;



            Dictionary<string, string> LibFuns = new Dictionary<string, string>();

            foreach (var item in all)
            {
                if (item.Key != "0")
                {
                    foreach (var item1 in item.Value)
                    {
                        try
                        {
                            LibFuns.Add(item1.Key, ReadFun(item1.Value.File, item1.Value.Location.iLine, item1.Value.Name));
                        }
                        catch
                        {

                            continue;
                        }

                    }

                }
            }
            return LibFuns;
        }
        /// <summary>
        /// 递归查找待插入的字符串
        /// </summary>
        /// <param name="text">待字符串</param>
        /// <param name="lib">内裤函数字典</param>
        /// <returns>要插入的字符串</returns>
        private string FindAllInsertText(string text, Dictionary<string, string> lib)
        {
            List<string> funlist = FindUserFuns(text);
            funlist.RemoveAll(data => !lib.ContainsKey(data));
            if (funlist.Count == 0)
            {
                return string.Empty;
            }
            else
            {
                string insertText = string.Empty;
                foreach (var item in funlist)
                {
                    string txt = string.Empty;
                    try
                    {
                        txt = lib[item];
                    }
                    catch
                    {

                    }

                    insertText += (txt + "\r\n");
                }

                return insertText + FindAllInsertText(text + "\r\n" + insertText, lib);
            }
        }

    }

}
